package cgs_worksheet

import (
	"cgs-server/helper"
	"cgs-server/server"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
	"io/ioutil"
	"net/http"
	"strings"
)

func init() {
	//server.Handle(http.MethodPost, "/api/Cgs/Worksheet/GetFilterData", GetFilterData, server.ListWorksheetRecord)
	//server.Handle(http.MethodPost, "/api/Cgs/Worksheet/GetFilterDataList", GetFilterDataList, server.ListWorksheetRecord)

	server.Post("/api/Cgs/Worksheet/GetFilterData", GetFilterData, "获取表单数据列表(工程配置)", server.None)
	server.Post("/api/Cgs/Worksheet/GetFilterDataList", GetFilterDataList, "获取表单数据列表(表单设计器)", server.Login)
}

// GetFilterData 某个表单数据，返回给在线编辑器用
func GetFilterData(w http.ResponseWriter, r *http.Request) {

	r.Body = http.MaxBytesReader(w, r.Body, int64(100<<20))

	s, _ := ioutil.ReadAll(r.Body)

	var filterParam FilterParam

	err := helper.FromJSON(s, &filterParam)

	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	//fmt.Printf("参数: %+v\n",filterParam)

	// 表 id
	id, err := primitive.ObjectIDFromHex(strings.TrimSpace(filterParam.Id))
	if err != nil {
		if !filterParam.WorksheetId.IsZero() {
			id = filterParam.WorksheetId
		} else {
			_, _ = helper.WriteJSON(w, server.CgsResult{
				Code: 300,
				Msg:  "id or worksheetID is required.",
			})
			return
		}
	}

	// 数据库
	db, err := server.Mongo()
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	filter := bson.D{
		{"id", id},
		{"isDeleted", 0},
	}

	worksheetInfo := WorksheetInfo{}

	find, _ := db.FindOne(server.CgsWorksheetInfoCollectionName, filter, &worksheetInfo)
	if !find {
		_, _ = helper.WriteJSON(w, server.CgsResult{
			Code: 300,
			Msg:  "Worksheet is not exist.",
		})
		return
	}

	// 字段限制
	projection := bson.D{
		{"_id", 0},
	}
	for i := 0; i < len(worksheetInfo.Fields); i++ {
		ws := worksheetInfo.Fields[i]
		if ws.Options["hidden"] != nil {
			if ws.Options["hidden"].(bool) == false {
				projection = append(projection, bson.E{Key: ws.Name, Value: 1})
			}
		} else {
			projection = append(projection, bson.E{Key: ws.Name, Value: 1})
		}
	}

	// 选项, 默认好像是按修改时间正序排列，最后修改的在最后面
	opts := options.FindOptions{
		Sort: bson.M{
			"updateTime": -1,
		},
	}

	// 分页
	pageNo := filterParam.PageNo
	pageSize := filterParam.PageSize
	skip := int64(0)
	if pageSize > 0 {
		if pageNo > 0 {
			skip = (pageNo - 1) * pageSize
		} else {
			pageNo += 1
		}
		opts.Skip = &skip
		opts.Limit = &pageSize
	}

	// 排序
	sortField := filterParam.SortField
	isAsc := -1
	if filterParam.IsAsc {
		isAsc = 1
	}
	if sortField != "" {
		opts.Sort = bson.M{
			sortField: isAsc,
		}
	}

	//opts.SetLimit(10000)
	opts.SetProjection(projection)

	filter = filterParam.GetFilterParam(&worksheetInfo)
	//fmt.Printf("过滤条件: %v\n", filter)
	filter2 := bson.E{Key: "$or", Value: bson.A{
		bson.D{{"isDeleted", 0}},
		bson.D{{"isDeleted", nil}},
	}}
	filter = append(filter, filter2)

	// 表的数据库名称
	collectionName := filterParam.WsCollection

	if collectionName == "" {
		// 根据 id 去查表的数据库名称
		collectionName = worksheetInfo.WsCollection
	}

	var doc = bson.A{}

	_ = db.FindMany(collectionName, filter, &doc, &opts)

	// 格式化时间
	doc = FormatDataType(doc, worksheetInfo)

	resultArr := bson.A{}

	data := bson.M{}
	for _, fv := range worksheetInfo.Fields {

		if fv.Options["hidden"] != nil {
			if fv.Options["hidden"].(bool) == true {
				continue
			}
		}

		data = bson.M{
			"name":     fv.Name,
			"alia":     fv.Alia,
			"dataType": fv.DataType,
			"options":  fv.Options,
		}

		arr := bson.A{}
		flag := false
		for _, i := range doc {
			rs := primitive.M{}

			if v, ok := i.(primitive.D); ok {
				rs = v.Map()
			} else {
				rs = i.(primitive.M)
			}
			for k, v := range rs {
				if k == fv.Name {
					arr = append(arr, v)
					flag = true
					break
				}
			}
			if !flag {
				//switch fv.DataType.(int32) {
				//case 5:
				//	arr = append(arr, 0)
				//default:
				//	arr = append(arr, "")
				//}

				arr = append(arr, "")
			}
		}
		data["data"] = arr

		resultArr = append(resultArr, data)
	}

	_, _ = helper.WriteJSON(w, server.OK("Get Successfully!").WithData(resultArr))

}

// GetFilterDataList 返回给表单设计器，展示用
func GetFilterDataList(w http.ResponseWriter, r *http.Request) {
	r.Body = http.MaxBytesReader(w, r.Body, int64(100<<20))

	s, _ := ioutil.ReadAll(r.Body)

	var filterParam FilterParam

	err := helper.FromJSON(s, &filterParam)

	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	//fmt.Printf("参数: %+v\n",filterParam)

	// 表 id
	id, err := primitive.ObjectIDFromHex(strings.TrimSpace(filterParam.Id))
	if err != nil {
		_, _ = helper.WriteJSON(w, server.CgsResult{
			Code: 300,
			Msg:  "NodeId is not allowed empty.",
		})
		return
	}

	// 数据库
	db, err := server.Mongo()
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	filter := bson.D{
		{"id", id},
	}

	worksheetInfo := WorksheetInfo{}

	find, _ := db.FindOne(server.CgsWorksheetInfoCollectionName, filter, &worksheetInfo)
	if !find {
		_, _ = helper.WriteJSON(w, server.CgsResult{
			Code: 300,
			Msg:  "Worksheet is not exist.",
		})
		return
	}

	// 字段限制
	projection := bson.D{
		{"_id", 0},
	}
	hasSortField := false
	for i := 0; i < len(worksheetInfo.Fields); i++ {
		ws := worksheetInfo.Fields[i]
		if ws.Options["hidden"] != nil {
			if ws.Options["hidden"].(bool) == true {
				projection = append(projection, bson.E{Key: ws.Name, Value: 0})
			}
		}
		if ws.Name == "sortField" {
			hasSortField = true
		}
	}

	// 分页
	pageNo := filterParam.PageNo
	pageSize := filterParam.PageSize

	skip := int64(0)
	if pageNo > 0 {
		skip = (pageNo - 1) * pageSize
	} else {
		pageNo += 1
	}
	if pageSize == 0 {
		pageSize = 100
	}

	// 选项
	opts := options.FindOptions{
		Skip:       &skip,
		Limit:      &pageSize,
		Projection: projection,
		Sort: bson.M{
			"updateTime": -1,
		},
	}

	// 如果有 sortField 字段，根据这个排序，避免由于updateTime值一样造成排序混乱的情况
	if hasSortField {
		opts.Sort = bson.M{
			"sortField": 1,
		}
	}

	// 排序
	sortField := filterParam.SortField
	isAsc := -1
	if filterParam.IsAsc {
		isAsc = 1
	}
	if sortField != "" {
		opts.Sort = bson.M{
			sortField: isAsc,
		}
	}

	filter = filterParam.GetFilterParam(&worksheetInfo)
	//fmt.Printf("过滤条件: %v\n", filter)
	filter2 := bson.E{Key: "$or", Value: bson.A{
		bson.D{{"isDeleted", 0}},
		bson.D{{"isDeleted", nil}},
	}}
	filter = append(filter, filter2)

	// 表的数据库名称
	collectionName := filterParam.WsCollection

	if collectionName == "" {
		// 根据 id 去查表的数据库名称
		collectionName = worksheetInfo.WsCollection
	}

	var doc = bson.A{}

	count, _ := db.Count(collectionName, filter)
	_ = db.FindMany(collectionName, filter, &doc, &opts)

	// 格式化时间
	docs := FormatDataType(doc, worksheetInfo)

	result := server.PageResult{
		CgsResult: server.CgsResult{
			Code: 200,
			Msg:  "Get Successfully!",
			Data: docs,
		},
		PageNo:     pageNo,
		PageSize:   pageSize,
		TotalCount: count,
	}
	result.CalculateTotalPage()

	_, _ = helper.WriteJSON(w, result)
}

func FormatDataType(arr bson.A, info WorksheetInfo) bson.A {
	docs := bson.A{}
	for _, v := range arr {
		value := v.(primitive.D).Map()
		dataMap := bson.M{}

		for key, val := range value {
			if val == nil {
				continue
			}

			dataType := info.GetDataType(key)
			opts := info.GetOptions(key)

			switch dataType {
			case DATE:
				if _, ok := val.(string); ok {
					dataMap[key] = val
					continue
				}
				if opts != nil {
					format := opts["format"].(string)
					timeStr := helper.Format(val.(primitive.DateTime).Time(), format)
					dataMap[key] = timeStr
				} else {
					timeStr := helper.Format(val.(primitive.DateTime).Time(), "YYYY-MM-DD HH:mm:ss")
					dataMap[key] = timeStr
				}
			case TIME:
				if _, ok := val.(string); ok {
					dataMap[key] = val
					continue
				}
				if opts != nil {
					format := opts["format"].(string)
					timeStr := helper.Format(val.(primitive.DateTime).Time(), format)
					dataMap[key] = timeStr
				} else {
					timeStr := helper.Format(val.(primitive.DateTime).Time(), "HH:mm:ss")
					dataMap[key] = timeStr
				}
			default:
				dataMap[key] = val
			}
		}

		docs = append(docs, dataMap)
	}

	return docs
}
